#pragma once

#include <vector>
#include <queue>
#include "Cond.hpp"
#include "Mutex.hpp"
#include "Log.hpp"
#include "Thread.hpp"

namespace ThreadPoolModule
{
    using namespace ThreadModule;
    using namespace CondModule;
    using namespace MutexModule;
    using namespace LogModule;

    static const int gnum = 5; // 默认线程数

    template <typename T>
    class ThreadPool
    {
    private:
        // 唤醒所有线程
        void WakeUpAllThreads()
        {
            LockGuard lockguard(_mutex);

            if (_sleepernum == 0) // 如果没有睡眠线程, 直接返回
                return;
            _cond.Broadcast();
            LOG(LogLevel::INFO) << " 唤醒所有睡眠线程";
        }

        // 唤醒一个线程
        void WakeUpOne()
        {
            _cond.Signal(); // 唤醒一个线程

            LOG(LogLevel::INFO) << " 唤醒了一个睡眠线程"; // 打印日志
        }

        // 构造函数
        ThreadPool(int num = gnum) : _num(num), _isrunning(false), _sleepernum(0)
        {
            for (int i = 0; i < num; i++)
            {
                _threads.emplace_back(
                    [this]()
                    {
                        HandlerTask();
                    });
            }
        }

        ThreadPool(const ThreadPool<T> &) = delete;               // 禁止拷贝构造函数
        ThreadPool<T> &operator=(const ThreadPool<T> &) = delete; // 禁止拷贝赋值函数

    public:
        // 获取线程池实例
        static ThreadPool<T> *GetInstance()
        {
            if (inc == nullptr)
            {
                LockGuard lockguard(_lock);
                LOG(LogLevel::INFO) << " 获取实例...";
                if (inc == nullptr) // 若线程池实例不存在, 构造线程池实例
                {
                    LOG(LogLevel::INFO) << " 首次构造实例...";
                    inc = new ThreadPool<T>(); // 构造线程池实例
                    inc->Start();              // 启动线程池
                }
            }

            return inc;
        }

        // 线程启动
        void Start()
        {
            if (_isrunning)
                return; // 线程池已经启动, 直接返回

            // 线程池未启动, 启动线程池
            _isrunning = true;
            for (auto &t : _threads)
            {
                t.Start();
                LOG(LogLevel::INFO) << " 启动线程: " << t.Name();
            }
        }

        // 线程停止
        void Stop()
        {
            if (!_isrunning)
                return; // 线程池未启动, 直接返回
            // 线程池正在运行, 停止线程池
            _isrunning = false;

            WakeUpAllThreads(); // 唤醒所有线程
        }

        // 等待所有线程退出
        void join()
        {
            for (auto &t : _threads)
            {
                t.Join();
            }
        }

        // 添加任务, 任务入队
        bool Enqueue(const T &in)
        {
            if (_isrunning) // 线程池正在运行, 入队任务
            {
                // 上锁
                LockGuard lockguard(_mutex);

                // 入队
                _taskq.push(in);

                // 若线程全部处于睡眠状态, 唤醒一个线程
                if (_threads.size() == _sleepernum)
                {
                    WakeUpOne();
                }

                return true;
            }
            return false; // 线程池未启动, 无法入队任务
        }

        // 线程处理函数
        void HandlerTask()
        {
            char name[128];
            pthread_getname_np(pthread_self(), name, sizeof(name));

            /*//打印日志
            while(1)
            {
                sleep(1);
                LOG(LogLevel::DEBUG) << "Thread: "<< name << " is running..." ;
            }*/

            // 处理任务
            while (1)
            {
                T t;
                {
                    LockGuard lockguard(_mutex);
                    while (_taskq.empty() && _isrunning) // 如果任务队列为空或线程池未停止, 则等待
                    {
                        _sleepernum++;
                        _cond.Wait(_mutex);
                        _sleepernum--;
                    }

                    // 线程池停止且任务为空, 唤醒线程并退出
                    if (_taskq.empty() && !_isrunning)
                    {
                        LOG(LogLevel::INFO) << "Thread: " << name << " 退出, 线程池停止且任务为空";
                        break;
                    }

                    // 线程池未停止且任务不为空, 唤醒线程并处理任务
                    t = _taskq.front();
                    _taskq.pop();
                }
                t(); // 执行任务
            }
        }

        // 析构函数
        ~ThreadPool()
        {
        }

    private:
        std::vector<Thread> _threads; // 线程池
        int _num;                     // 线程数量

        std::queue<T> _taskq; // 任务队列

        Cond _cond;   // 条件变量
        Mutex _mutex; // 互斥锁

        bool _isrunning; // 线程池是否正在运行
        int _sleepernum; // 睡眠线程数量

        static ThreadPool<T> *inc; // 单例指针
        static Mutex _lock;        // 单例锁
    };

    template <typename T>
    ThreadPool<T> *ThreadPool<T>::inc = nullptr; // 线程池实例
    template <typename T>
    Mutex ThreadPool<T>::_lock; // 单例锁
}